﻿using System;
using System.Linq;
using Nancy;
using Nancy.ModelBinding;
using Omu.ValueInjecter;
using Wolfpack.Periscope.Core.Interfaces;
using Wolfpack.Periscope.Core.Interfaces.Entities;
using Wolfpack.Periscope.Core.Interfaces.Events;
using Wolfpack.Periscope.Core.Interfaces.Messages;

namespace Wolfpack.Periscope.Core.Modules
{
    public class DashboardModule : NancyModule
    {
        private readonly IDashboard _dashboard;

        public DashboardModule(IDashboard dashboard)
            : base("/dashboard")
        {
            _dashboard = dashboard;

            // ===================================================================
            // UI methods
            // ===================================================================
            Get["/{name?}"] = _ =>
            {
                var options = this.Bind<PanelOptions>();

                var panelName = (string) _.name;
                if (string.IsNullOrWhiteSpace(panelName))
                    panelName = _dashboard.Configuration.Panels.OrderBy(p => p.Sequence).First().Name;

                var model = new
                {
                    Debug = options.Debug.ToString().ToLower(),
                    PanelName = panelName
                };
                return View["default.sshtml", model];
            };
            Get["/manage/panels"] = _ => View["panel-manager.sshtml"];
            Get["/manage/widgets"] = _ => View["widget-manager.sshtml"];
            Get["/push"] = _ => View["push-message.sshtml"];
            Get["/about"] = _ => View["about.sshtml"];

            // ===================================================================
            // API/data methods
            // ===================================================================
            Get["/panel/{name}"] = _ =>
            {
                var panelName = (string) _.name;
                var panel = _dashboard.RenderPanel(panelName);
 
                var response = new PanelResponse();
                response.InjectFrom<LoopValueInjection>(panel);
                return Response.AsJson(response);
            };
            Get["/panel/{id}/widgets"] = _ =>
            {
                var panelId = new Guid((string)_.id);

                var widgets = _dashboard.Configuration.Panels
                    // should only be one
                    .Where(x => x.Id.Equals(panelId))
                    .SelectMany(x => x.Widgets);
 
                return Response.AsJson(widgets);
            };
            Get["/panel/list"] = _ =>
            {
                var panels = _dashboard.Configuration.Panels.Select(x => new
                {
                    x.Id,
                    x.Name,
                    x.Sequence,
                    x.DwellInSeconds,
                    Widgets = x.Widgets.Select(y => new
                    {
                        y.Id
                    })
                });
                return Response.AsJson(panels);
            };
            Post["/panel/loaded"] = _ =>
            {
                var request = this.Bind<PanelReference>();
                _dashboard.Infrastructure.MessageBus.PublishAsync(new PanelLoadedEvent(this, request));
                return Response.AsJson(new { Message = "Success" }); 
            };
            Post["/panel/add"] = _ =>
            {
                var request = this.Bind<AddPanelRequest>();
                _dashboard.Infrastructure.MessageBus.PublishAsync(new AddPanelToDashboardCommand(this, request));
                return Response.AsJson(new { Message = "Success" }); 
            };
            Post["/panel/layout/changed"] = _ =>
            {
                var request = this.Bind<PanelLayoutChangeRequest>();
                _dashboard.Infrastructure.MessageBus.PublishAsync(new PanelLayoutChangeRequestEvent(this, request));
                return Response.AsJson(new { Message = "Success" }); 
            };




            Get["/widget/list"] = _ =>
            {
                var widgets = _dashboard.Configuration.Panels.SelectMany(p =>
                {
                    var panel = _dashboard.RenderPanel(p.Name);
                    return panel.Widgets.Select(w => new
                    {
                        PanelId = panel.Id,
                        PanelName = panel.Name,
                        WidgetId = w.Id,
                        w.SampleMessage
                    });
                })
                .ToList();

                return Response.AsJson(widgets);
            };
            Post["/widget/add"] = _ =>
            {
                var request = this.Bind<AddWidgetRequest>();
                _dashboard.Infrastructure.MessageBus.PublishAsync(new AddWidgetToPanelCommand(this, request));
                return Response.AsJson(new { Message = "Success", Success = true });
            };

            Post["/widget/resize"] = _ =>
            {
                var request = this.Bind<WidgetResizeRequest>();
                _dashboard.Infrastructure.MessageBus.Publish(new WidgetResizeCommand(this, request));
                return Response.AsJson(new { Message = "Success", Success = true });
            };            
            
            Post["/widget/update"] = _ =>
            {
                var update = this.Bind<WidgetUpdateRequest>();
                if (update.Timestamp == DateTime.MinValue)
                    update.Timestamp = DateTime.UtcNow;

                _dashboard.Infrastructure.Logger.LogDebug("\t{0}->{1}", 
                    update.Origin,
                    update.TargetWidgetId);

                _dashboard.Infrastructure.MessageBus.PublishAsync(new WidgetUpdateCommand(this, update));
                return Response.AsJson(new { Message = "Success" }, HttpStatusCode.Accepted);
            };
        }
    }
}